#pragma once
#include <unordered_map>
#include <pthread.h>
#include "util.hpp"
#include "config.hpp"

namespace Cloud
{
    typedef struct BackupInfo
    {
        bool pack_flag;        // 文件是否已经压缩
        size_t fsize;          // 文件大小
        time_t mtime;          // 文件最后修改时间
        time_t atime;          // 文件最后访问时间
        std::string real_path; // 实际存储路径
        std::string pack_path; // 文件压缩存储路径
        std::string url;
        // 填充信息
        void SetBackupInfo(const std::string &realpath)
        {
            Cloud::Config *config = Cloud::Config::GetInstance();
            std::string packdir = config->GetPackDir();
            std::string packsuffix = config->GetPackfileSuffix();
            std::string download_prefix = config->GetDownloadPrefix();
            this->pack_flag = false;
            Cloud::FileUtil fu(realpath);
            this->fsize = fu.FileSize();
            this->mtime = fu.LastMTime();
            this->atime = fu.LastAtime();
            this->real_path = realpath;
            //  ./backupdir/test.txt  --->./packdir/test.txt.lz
            this->pack_path = packdir + fu.FileName() + packsuffix;
            //  ./backupdir/test.txt  --->./download/test.txt
            this->url = download_prefix + fu.FileName();
        }
    } BackupInfo;
    class DataManager
    {
    public:
        DataManager()
        {
            this->_backup_file = Cloud::Config::GetInstance()->GetBackupFile();
            pthread_rwlock_init(&_rwlock, nullptr);
            InitLoad();
        }
        ~DataManager()
        {
            pthread_rwlock_destroy(&_rwlock);
        }
        bool Insert(const BackupInfo &info)
        {
            // 添加信息，加写入锁
            pthread_rwlock_wrlock(&_rwlock);
            _table[info.url] = info;
            pthread_rwlock_unlock(&_rwlock);
            Storage();
            return true;
        }
        bool Updata(const BackupInfo &info)
        {
            pthread_rwlock_wrlock(&_rwlock);
            _table[info.url] = info;
            pthread_rwlock_unlock(&_rwlock);
            Storage();
            return true;
        }
        // 通过一个url获取文件信息
        bool GetOneByURL(const std::string &url, BackupInfo *info)
        {
            pthread_rwlock_wrlock(&_rwlock);
            // url是key值所以直接用find查找
            auto it = _table.find(url);
            if (it == _table.end())
            {
                pthread_rwlock_unlock(&_rwlock);
                return false;
            }
            *info = it->second;
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }
        // 通过一个实际的存储路径来获取文件信息
        bool GetOneByRealPath(const std::string &realpath, BackupInfo *info)
        {
            pthread_rwlock_wrlock(&_rwlock);
            auto it = _table.begin();
            for (; it != _table.end(); ++it)
            {
                if (it->second.real_path == realpath)
                {
                    *info = it->second;
                    pthread_rwlock_unlock(&_rwlock);
                    return true;
                }
            }
            pthread_rwlock_unlock(&_rwlock);
            return false;
        }
        // 获取所有备份文件信息并放入vector容器
        bool GetAll(std::vector<BackupInfo> *arry)
        {
            pthread_rwlock_wrlock(&_rwlock);
            auto it = _table.begin();
            for (; it != _table.end(); ++it)
            {
                arry->push_back(it->second);
            }
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }

        // 数据持久化存储，将数据存放到文件中
        bool Storage()
        {
            // 获取所有数据
            std::vector<BackupInfo> arr;
            this->GetAll(&arr);
            // 添加到Json::Value中
            Json::Value root;
            for (int i = 0; i < arr.size(); ++i)
            {
                Json::Value item;
                item["pack_flag"] = arr[i].pack_flag;
                //Json只重载了基础数据类型，所以需要进行强转
                item["fsize"] = (Json::Int64)arr[i].fsize;
                item["mtime"] = (Json::Int64)arr[i].mtime;
                item["atime"] = (Json::Int64)arr[i].atime;
                item["real_path"] = arr[i].real_path;
                item["pack_path"] = arr[i].pack_path;
                item["url"] = arr[i].url;
                root.append(item);
            }
            //对Json::Value 序列化
            std::string body;
            if(Cloud::JsonUtil::Serialize(root,&body) == false)
            {
                std::cerr<<"Storage() Serialize failed!"<<std::endl;
                return false;
            }
            //将序列化后的内容写入文件
            Cloud::FileUtil fu(_backup_file);
            fu.SetContent(body);
            return true;
        }
        //初始化加载
        bool InitLoad()
        {
            //将cloud.bat中的数据读取出来
            Cloud::FileUtil fu(_backup_file);
            if(fu.Exists() == false)
            {
                //cloud.bat 文件不存在的话就不用加载了
                return true;
            }
            std::string body;
            fu.GetContent(&body);
            //反序列化
            Json::Value root;
            if(Cloud::JsonUtil::Deserialize(body,&root) == false)
            {
                std::cerr<<"InitLoad() Deserizlize failed!"<<std::endl;
                return false;
            }
            //将反序列化得到的数据添加到_table表中
            for(int i=0;i<root.size();i++)
            {
                Cloud::BackupInfo info;
                info.pack_flag=root[i]["pack_flag"].asBool();
                info.fsize=root[i]["fsize"].asInt64();
                info.mtime=root[i]["mtime"].asInt64();
                info.atime=root[i]["atime"].asInt64();
                info.pack_path=root[i]["pack_path"].asString();
                info.real_path=root[i]["real_path"].asString();
                info.url=root[i]["url"].asString();
                this->Insert(info);
            }
            return true;
        }

    private:
        pthread_rwlock_t _rwlock;
        // key:url val:backupInfo
        std::unordered_map<std::string, BackupInfo> _table;
        //存放备份文件信息文件的文件名
        std::string _backup_file;
    };
}
